#include "types.h"
#include "riscv.h"
#include "defs.h"
#include "spinlock.h"
#include "proc.h"   // mycpu(), cpuid()

// 读取 SIE 状态
int
intr_get(void)
{
  return (r_sstatus() & SSTATUS_SIE) != 0;
}

void
intr_on(void)
{
  w_sstatus(r_sstatus() | SSTATUS_SIE);
}

void
intr_off(void)
{
  w_sstatus(r_sstatus() & ~SSTATUS_SIE);
}

// 关闭中断并记录嵌套计数
void
push_off(void)
{
  int old = intr_get();
  intr_off();
  struct cpu *c = mycpu();
  if (c->noff == 0)
    c->intena = old;
  c->noff += 1;
}

// 恢复中断嵌套计数，并在最外层按需恢复中断
void
pop_off(void)
{
  struct cpu *c = mycpu();
  if (intr_get())
    panic("pop_off - interruptible");
  if (c->noff < 1)
    panic("pop_off");
  c->noff -= 1;
  if (c->noff == 0 && c->intena)
    intr_on();
}

void
initlock(struct spinlock *lk, char *name)
{
  lk->name = name;
  lk->locked = 0;
  lk->cpu = -1;
}

// 当前CPU是否持有该锁
int
holding(struct spinlock *lk)
{
  return lk->locked && (lk->cpu == cpuid());
}

void
acquire(struct spinlock *lk)
{
  push_off();
  if (holding(lk))
    panic("acquire");

  // 原子自旋获取
  while (__sync_lock_test_and_set(&lk->locked, 1) != 0)
    ;

  __sync_synchronize();
  lk->cpu = cpuid();
}

void
release(struct spinlock *lk)
{
  if (!holding(lk))
    panic("release");

  lk->cpu = -1;
  __sync_synchronize();
  __sync_lock_release(&lk->locked);

  pop_off();
}